????ࡱ> 9 Rgbjbj2cl2 $ 2] 6 $ Z       K2 x >-0][[22 HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/0309mcgee.html" http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/0309mcgee.html Moving from the BDE and dbExpress to ADO.NET and the Borland Data Provider  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "authorname" Jeremy McGee September 2003 2003 International Business Machines Corporation. All rights reserved. Table of Contents  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "introduction" Introduction  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section1" Using ADO.NET: visual or non-visual?  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section2" A quick overview  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section3" Connecting with DBConnection  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section4" How the different data providers are implemented  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section5" Executing queries with DbCommand  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section6" Accessing DbCommand data directly with a DataReader  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section7" DbDataAdapters and DataSets  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "section8" Moving from the BDE to ADO.NET and BDP  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/" \l "conclusion" ConclusionIntroduction If you've used Borland Delphi, C++Builder or Kylix, you'll know that to connect to databases such as IBM DB2 Universal DatabaseTM (UDB), it's most convenient to use some components from the Borland Visual Component Library (VCL). With Borland C#BuilderTM, everything changes: instead of the Borland VCL, you'll need to use the Microsoft .NET Framework, and in particular ADO.NET, rather than the Borland Database Engine or dbExpress. Bob Swart's two articles on connecting to DB2 UDB data illustrate just how easy C#Builder makes it to create a simple database application that uses the Borland Data Provider (BDP) and ADO.NET. (The  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0305swart1/0305swart1.html" first article shows how to connect the BDP components visually to create a simple user interface. The  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0306swart/0306swart.html" second article goes into more detail on the DataSet class.) In this article, we'll look at just what all those ADO.NET classes and interfaces can do for us. We'll use C#Builder Enterprise, DB2 UDB, and the IBM Managed Data Provider for the Microsoft .NET Framework. Note that we'll use the DB2 managed code provider for some of the samples. To install this, you'll need the Windows client of DB2 UDB 8.1 FixPak 3 or better, which installs the Microsoft .NET Framework DB2 UDB driver. If you're using C#Builder, you'll need to add the IBM.Data.DB2 assemblyuse Project | Add Reference, then select Browse?/b> and navigate to the IBM DB2 .NET Framework 1.1 assembly. This is installed by default in C:\Program Files\IBM\SQLLIB\BIN\netf11. Where necessary, I'll use the regular DB2 UDB sample database. Using ADO.NET: visual or non-visual? One of the major challenges that users of the VCL immediately encounter with the .NET Framework is that there's no equivalent to the data module. This means that visually, with the user interface, there is no easy way to refer to an object on one form from another. There are plenty of alternative options, but all of them depend on code. In this article, I've included code samples to give you pointers on what to do, as thankfully, like the VCL, one of the impressive aspects of ADO.NET is that it's very easy to create database access logic through program code. The code samples will all use C#. Once you understand the program code (and in particular the subtleties of interfaces and classes), it's then quite simple to write 'wrapper' classes around the database access logic. If this is done in the right way, the result is 'business logic' classes that handle all the database access, but which can be used throughout the application. A good example of this is in the IBuySpy application that we discussed in a  HYPERLINK "http://www-106.ibm.com/developerworks/db2/library/techarticle/0308mcgee/0308mcgee.html" previous article. A quick overview Here's a simplified architectural view of ADO.NET as compared with the BDE. Figure 1. A simple view of how ADO.NET compares with the BDE  INCLUDEPICTURE "http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/images/figure1.gif" \* MERGEFORMATINET  If you're accustomed to the VCL components, then you'll find that the principles behind ADO.NET are quite straightforward. ADO.NET might seem very different, but most features are therethey're just in a different place. Connecting with DBConnection The first class returns a database connection object. This is used by all of the other components as a handle to refer to the connection. For example, in the C# language, for IBM DB2 using the DB2 managed provider: DB2Connection myConn = new IBM.Data.DB2.DB2Connection("DATABASE = SAMPLE; UID=; PWD=;"); Once the handle has been assigned, it's possible to open it, use it as the Connection property of queries or stored procedures, and then close it. For example: DB2Connection myConn = new IBM.Data.DB2.DB2Connection("DATABASE = SAMPLE; UID=; PWD=;"); string myInsertQuery = "INSERT INTO STAFF (ID, NAME) Values(1002,"Jane Doe")"; DB2Command myComm = new DB2Command(myInsertQuery); myComm.Connection = myConn; myConn.Open(); myComm.ExecuteNonQuery(); myConn.Close(); We'll cover the DB2Command object later. Immediately, we can see an important distinction between ADO.NET and the VCL. To connect to a database with (say) the BDE, we'd use a TDatabase component, no matter what the underlying database might happen to be. With ADO.NET, we use a specialized variant of the data access component for each database server. How the different data providers are implemented The way that database access classes are specialized for each type of database server is one of the major features of the design of ADO.NET. While the driver classes are different, all have the same basic capabilities and can often be used interchangeably. The trick is accomplished through interfaces that define the database-specific classes. An application that uses the IBM.Data.DB2 managed provider to access data on a DB2 server will use a DB2Connection component, as in the example above. A similar component, SqlConnection, is available for SQL Server: SqlConnection myConn = new System.Data.SqlClient.SqlConnection("Persist Security Info=False;Integrated Security=SSPI;database=northwind;server=mySQLServer"); For Oracle, there's an OracleConnection component: OracleConnection myConn = new System.Data.OracleClient.OracleConnection("Data Source=Oracle8i;Integrated Security=yes"); Each of these components has a basic set of properties, methods, and events that is the same: in other words, they share the same interface. For database connections the interface is IDbConnection, documented in the Microsoft .NET Framework help. This interface defines the minimum level of capabilities; in practice, each component will most likely have additional properties, methods, and events to support special features of that particular database or driver. For example, the DB2Connection component includes an additional method that can be used to force connection pool resources to be released. By default, ADO.NET providers can share and reuse connections, which saves resources but can also mean that connections are left open for possible reuse. This method gives you additional control that isn't available through drivers such as the SQL Server managed provider. While database-specific components give great flexibility, they don't result in portable code. This might be a nuisance should you want to switch from one database to another. With that in mind, Borland has created the Borland Data Provider (BDP). The BDP is a regular managed .NET data provider, with a difference. Instead of working with just one kind of database, it can work with a range of different servers. The actual driver is determined through the connection string passed to the BdpConnection object when it is created (or the ConnectionString property). So to connect to SQL Server using the BDP, you might use: BdpConnection myConn = new Borland.Data.Provider.BdpConnection("assembly=Borl and.Data.Mssql,Version=1.1.0.0, Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b;ve ndorclient=sqloledb.dll; osauthentication=False;database=;usernam e=;hostname=; password=;provider=MSSQL"); Note that the host name is embedded in the connection string for this particular driver. That isn't necessary for the DB2 driver, where you'd use: BdpConnection myConn = new Borland.Data.Provider.BdpConnection("assembly=Borl and.Data.Db2,Version=1.1.0.0, Culture=neutral,PublicKeyToken=91d62ebb5b0d1b1b;ve ndorclient=db2cli.dll; database=;username=; password=;provider=DB2"); While the connection syntax is slightly different, the object returned is the same. That means that all the other code is unchanged. You can even store this string in a resource file and refer to it at runtime. Borland provides a Connections Editor that can be used by the forms designer to create the connection strings. I can create a second project in another instance of C#Builder, place a bdpConnection object on a Windows Form, and use the clipboard to copy the connection string into a resource file for the application I'm writing. Internally, in most cases, the BDP calls the same native client libraries as the server-specific components, so it's just as fast. The DbConnection classes correspond roughly to the BDE TDatabase or dbExpress TSQLConnection components. Like these components, DbConnection is the point where transactions are managed. The approach to transaction management is quite different: the BeginTransaction method for the DbConnection classes returns a transaction object, which can be used as a property for later SQL commands. Executing queries with DbCommand Once the connection is open, ADO.NET includes components to run queries directly against the database. Like the DbConnection classes, DbCommand is an abstract interface that has server-specific implementations. We've seen this example already: DB2Connection myConn = new IBM.Data.DB2.DB2Connection("DATABASE = SAMPLE"); string myInsertQuery = "INSERT INTO STAFF (ID, NAME) Values(1002,"Jane Doe")"; DB2Command myComm = new DB2Command(myInsertQuery); myComm.Connection = myConn; myConn.Open(); myComm.ExecuteNonQuery(); myConn.Close(); As we can see, the DB2Commandthe DB2-specific flavor of DbCommandcan be used to run a query directly on a DB2 server. There's a BDP equivalent too, so BdpConnection myConn = new Borland.Data.Provider.BdpConnection(connectionstring); string myInsertQuery = "INSERT INTO STAFF (ID, NAME) Values(1002,"Jane Doe")"; BdpCommand myComm = new BdpCommand(myInsertQuery); myComm.Connection = myConn; myConn.Open(); myComm.ExecuteNonQuery(); myConn.Close(); would run on any server for which there's a BDP driver. An SQL INSERT command doesn't return a result but can take parameters. ADO.NET can include parameters using the DbDataParameter classes through the Parameter property. The parameter classes are, yet again, implemented on a server-specific basis. Here is an example of parameters, which calls a DB2 stored procedure to return the full name from a database, given an email address. First, the stored procedure: CREATE PROCEDURE Job( IN v_Name VARCHAR(50), OUT v_Job VARCHAR(50)) DYNAMIC RESULT SETS 1 LANGUAGE SQL BEGIN SELECT Job INTO v_Job FROM Staff WHERE Name = v_Name FETCH FIRST 1 ROWS ONLY; END Following the C# code fragment. We create the connection, create a command, then create two BdpParameter objects and add them to the command object. public String GetJob(String Name) { BdpConnection myConn = new BdpConnection(); BdpCommand myCommand = new BdpCommand("Job", myConn); // This is a stored procedure - mark the command accordingly myCommand.CommandType = CommandType.StoredProcedure; // Add the input parameter BdpParameter paramName = new BdpParameter("V_NAME", BdpType.String, 50); paramName.Direction = ParameterDirection.Input; paramName.Precision = 50; myCommand.Parameters.Add(paramName); // The output parameter BdpParameter paramJob = new BdpParameter("V_JOB", BdpType.String, 50); paramJob.Direction = ParameterDirection.Output; paramJob.Precision = 50; myCommand.Parameters.Add(paramJob); paramName.Value = Name; myConn.Open(); myCommand.ExecuteNonQuery(); myConn.Close(); // The return value is passed as an Object. We need to cast as a string return (string)paramJob.Value; } Here are a couple of important notes. First, you should declare the parameters in the same order that they're declared in the stored procedure. Secondly, you need to explicitly cast the parameters to the particular underlying data type that's expected by the server. Here are examples of some of the different data types supported by the DB2 managed provider and the BDP: DB2 data typeDB2 managed providerBorland Data ProviderVARCHARDB2Type.VarCharBdpType.StringINTDB2Type.IntegerBdpType.Int16, BdpType.Int32, or BdpType.Int64, as neededIMAL (x, y)DB2Type.DecimalBdpType.DecimalTIMESTAMPDB2Type.TimeStampBdpType.DateTimeYou'll also need to set the Size and Precision properties for some of these data types as appropriate. This approach is quite different from the BDE and dbExpress, which uses the TQuery and TSQLQuery components to call stored procedures or other data-definition queries, which don't return a tabular result set. These should be replaced by DbCommand objects. However, as we'll see, SELECT queries will typically need to use either a DataReader or a DataSet if the data is to be updated. Accessing DbCommand data directly with a DataReader The examples I just listed for the DbCommand classes didn't return a data set. DbCommand can handle this, but you'll need to use the DataReader component to get to the data. At first glance, DataReader seems somewhat limited. You can only step forward, reading one record at a time, and there's no caching of data. However, these limitations are more than outweighed by its main feature, which is speedthe DataReader is extremely fast. It's surprising how often a program will use a SELECT query that's suitable for a DataReader. An example is to return a chunk of records from a table ready to display on a Web page: public String GetStaff(string Job) { BdpConnection myConn = new BdpConnection(); BdpCommand myCommand = new BdpCommand("SELECT NAME, YEARS FROM STAFF WHERE JOB=? FETCH FIRST 10 ROWS ONLY", myConn); BdpParameter paramJob = new BdpParameter("JOB", BdpType.String, 50); paramJob.Direction = ParameterDirection.Input; paramJob.Precision = 50; myCommand.Parameters.Add(paramJob); paramJob.Value = Job; myConn.Open(); BdpDataReader readerStaff = myCommand.ExecuteReader(); string staffList=""; while (readerStaff.Read()) { staffList += readerStaff.GetString(0)+" ("+readerStaff.GetInt16(1)+")
"; } readerStaff.Close(); myConn.Close(); return staffList; } This example uses the BDP. The syntax for the DB2 managed provider is very similar: just change the "Bdp? components to be "Db2? components and the BdpType.String to a DB2Type.VarChar. This example shows how to use parameters in the SELECT queryit's a very similar process to that used for stored procedures. You'll need to add the Parameter objects to the Command.Parameters property in the same order as the "?" placeholders are defined in the query. Note that we're explicitly telling the system what kinds of data to expect, making the code even faster. There's no equivalent to IDataReader with the BDE: while there is a UniDirectional property for TQuery, this only affects the BDE, not the underlying query on the database, so there's always a degree of buffering in place. The closest equivalent in dbExpress is the TSQLQuery component, which also returns a forward-only result set. However, as we've seen, retrieving result sets is easier with ADO.NET. DbDataAdapters and DataSets What if you want to cache data and browse through it interactively? That's what the DataSet object can do. This powerful object manages a local cache of data that's been retrieved from a database with a DbDataAdapter object. That cache can then be used as the data source for other visual .NET Framework components such as the DataGrid or TextBox. As it caches data, the DataSet object resembles the VCL TClientDataSet. However, it is much more powerful: for instance, it can store data from multiple tables. That means that when we set it up, we need to tell it what tables to expect and what columns will go into it. For example: // Create a new dataset DataSet StaffDataSet = new DataSet("DSStaff"); // Set up the columns for the table for the dataset DataColumn IDCol = new DataColumn("ID", typeof(short)); DataColumn NameCol = new DataColumn("NAME"); DataColumn YearsCol = new DataColumn("YEARS", typeof(short)); // Set up the table for the dataset and add the columns DataTable StaffTable = new DataTable("TabStaff"); StaffTable.Columns.AddRange(new DataColumn[] {IDCol, NameCol, YearsCol}); // Add the table to the dataset StaffDataSet.Tables.AddRange(new DataTable[] {StaffTable}); There are plenty of parameters you can use to fine tune the behavior of each of these objectssee the online help for a summary. I'm using the constructors that reduce the code needed to a minimum. Note that the DataSet component comes in just one flavor. No matter which managed provider you choose, the DataSet component is the same. Our code configures the DataSet but doesn't retrieve the data. To do that, we need a DbDataAdapter. Not only can this component retrieve data from the database, it can also put changed data back from the DataSet. Because it has also to map the different data types to the .NET Framework data types, the DbDataAdapter object comes in different flavors depending on the database server that's being used. To use the DbDataAdapter component, you'll typically want to set properties that define the queries used to retrieve, update, insert, and delete records. When you want the data to be updated, these queries will be called. Each of those queries is stored in a DbCommand object, so if you want to handle updates, you'll need to create four queries, each of which is parameterizedquite a handful. Things are simpler if you just want to read data, however. Here's a code snippet showing how to use the BDP to do this: BdpConnection myConn = new BdpConnection(ConnString); // Create a command object to retrieve data BdpCommand SelComm = new BdpCommand("SELECT ID, NAME, YEARS FROM STAFF", myConn); // Create the data adapter BdpDataAdapter StaffDA = new BdpDataAdapter(); // Point the data adapter to the command object to get data StaffDA.SelectCommand = SelComm; First, I set up the connection, and then I set up a BdpCommand object to retrieve the data. The DataAdapter is used to link this BdpCommand to the DataTable in the DataSet. As you might expect by now, the process for setting up the DB2DataAdapter is similar: replace the BDP components with their DB2 equivalents. With the DbDataAdapter created, you'll then need to fill the DataSet. Here's where there are some differences between the BdpDataAdapter and the other flavors. For the DB2DataAdapter and other server-specific drivers, you need to tell the DbDataAdapter to fill the DataSet in code yourself. For example, the following might be appropriate to add to the Open method of a form that uses the DB2 managed provider: StaffDA.Fill(StaffDataSet); this.dataGrid1.DataMember = "TabStaff"; this.dataGrid1.DataSource = StaffDataSet; The BDP makes life a little easier. An extra property, active, can be used to tell the DataAdapter to automatically fill a DataTable in a DataSet on request. So instead of setting properties in an Open method, the following can be added to code that runs when the connections are first set up: // Point the data adapter to the DataSet and the table within it StaffDA.DataSet = StaffDataSet; StaffDA.DataTable = StaffTable; // Tell the DataAdapter to automatically populate the table StaffDA.Active = true; A great side-effect of this is that the DataSet can be populated at design time, showing live data! Although this can only happen when the BdpDataAdapter is placed on the same form as the DataSet and the associated controls, it's a neat trick. In practice you may find that for larger systems, you'll use a central object to encapsulate the DataSet so you can share it among several forms. If you're coming from the BDE, you can consider the DataSet component to be a little like a TClientDataSet. There are some superficial similarities: like the TClientDataSet, the DataSet caches data locally on the workstation, which can be a very efficient way of working with data as data is read and updated in large chunks. And like the BDE when it returns a read-only result set, the DataAdapter gives the developer SQL queries to update the source database. However, under the surface the TClientDataSet is very different. Unlike the BDE TClientDataSet, a DataSet can cache multiple tables. The DataSet manages data internally as a relational view into an XML schema, so as a result it doesn't have a concept of a 'cursor' or current record. Instead, a current record pointer is managed by the data-binding layer. Another difference is the technique used to handle updates. TClientDataSet keeps a log of changes to the table, which can be a very convenient way of handling multiple levels of 'undo'. By contrast, when updated with data-bound controls DataSet stores the updates on a row-by-row basis, only retaining original versions of updated and deleted rows. Moving from the BDE to ADO.NET and BDP Here's a quick summary of the components that you'll want to look at if you're used to the BDE. This isn't exhaustive, and is naturally simplified, but it should help you see where to start. BDE componentWhat it doesADO.NET componentWhat it doesTSession alongside TDataBase Establishes connection to database and manages transactionsDB2Connection, BdpConnectionEstablishes connection to database and manages transactionsTtableManages a local cache of result set a tableNo direct equivalent. Use either a DataSet with DbDataAdapter or a DbCommand with a DataReaderDataSet creates a local cache of one or more tables based on queriesTqueryManages a local cache of a queryNo direct equivalent. Use either a DataSet / DbDataAdapter or a DbCommand / DataReaderDbCommand / DataReader manage a forward-only cursor into results of a queryTstoredProcExecutes a stored procedureDbCommandCan execute a stored procedure, optionally returning a result setTdataSourceConduit between datasets and data aware controlsNo direct equivalentData-aware controls link to columns in DataSet objectTDBText, TDBEdit, etc.Data-aware versions of Windows controlsUse regular Windows Forms All appropriate Windows Forms are data-awareConclusion ADO.NET is a rich, sophisticated database access library. While ADO.NET is quite different from the Borland Database Engine, the streamlined features of the Borland Data Provider make it a little easier to use. The BDP gives .NET developers who need to access DB2 an efficient and scalable way to create Windows client and Web applications. Disclaimer This article contains sample code. IBM grants you ("Licensee") a non-exclusive, royalty free, license to use this sample code. However, the sample code is provided as-is and without any warranties, whether EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. IBM AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE THAT RESULT FROM YOUR USE OF THE SOFTWARE. IN NO EVENT WILL IBM OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, EVEN IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  About the author  HYPERLINK "mailto:jeremy@mcgee.demon.co.uk" Jeremy McGee started writing applications using BASIC on the Commodore PET. He fondly remembers typesetting a book-length publication on an early Apple Mac with a refrigerator-sized laser printer attached. Since then he's variously been a DEC VAX sysadmin, a technical support engineer for Borland Paradox, and was part of the team that launched Borland Delphi in Europe. Jeremy now runs a consulting firm in Southampton, UK.  efg  rsTUabcdTUefghPQ p q ' ( ) *   ) * + , 8 : +,H*CJaJ5\o(0JjU jUY + , 9 ( 1[$\$D$$IfK  6  p634Ka$Ifg3A ,-?@S *%*{88999::':(:):0:1:@:A:O:P:Q:T:U:d:e::::::::::::::::::G]T]ƻ˻˻ƻ˻˻ƻ˻˻ƻ˻˻CJOJQJ^JaJCJaJ!B*CJOJPJQJ^JaJph5CJOJQJ\^JaJ6] jU5\0J jUBICcN^[$\$[$\$ S !"p$i%&&&0'P'''''(((()B)Y)[$\$^Y)~))v*+C,--..*/Z/z/////00001>1q11111[$\$^112333334 4D4_4c4455^5555 6 6'6q666666^[$\$6E7v7777777788Y8y8{899:(:$If[$\$^(:):1:A:P:Q:U:e::::::uooou<ooouooo$If$$IfF! A06    34ab  ::::::b;<==>?uooouffdfff[$\$$If$$IfF! A06    34ab  ???????@K@`@a@@@@@A)A*A9AVAqArAAAAAAAAB^BBB1B2B4BBeDEEEFsGHHHH ICIpIIIIJcJdJJJL[$\$^LLN2OOOOOP?PaPbP}PPPP QDRhSSS$TNTtUUUU1VHV^[$\$HVWY[a\\G]U]b]t]] $$Ifa$[$\$ T]U]a]b]s]t]]]]]]]]]]4^5^6^<^=^h^i^^^ _ ____5_6________`` ` `M`N`O`Z`[``````````aa1a2a^a_a`aeeeeͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼͼ#jp^5CJOJQJU\^JaJ!B*CJOJPJQJ^JaJphCJOJQJ^JaJCJaJ5CJOJQJ\^JaJ'5B*CJOJPJQJ\^JaJphB]]]]]5^6^=^i^^ _`ZZZZ``ZZZZ$If$$If\/& ""0(#634ab ___6_____` `N``0ZZZZ`ZZZZ$If$$If\/& ""0(#634ab N`O`[``````a2a_a`$ZZZZ` ZZZZ$If$$If\/& ""0(#634ab _a`akabbeeeg`^U^US^M$If[$\$$$If\/& ""0(#634abee,f-f9f:fggggĿo(CJaJ!B*CJOJPJQJ^JaJph0J5CJOJQJ\^JaJCJOJQJ^JaJjCJOJQJU^JaJ ggg3$$If#*634a01h2P. A!7"7#7$7%S DyK Whttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/0309mcgee.htmlyK http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/0309mcgee.html\Dd"Or  S NAzhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/images/figure1.gifFigure 1. A simple view of how ADO.NET compares with the BDEbZMHl;F\TZnZMHl;F\TPNG  IHDRNWPLTEvɖaxN|]6JN^芊trf(22픔ՠfNM!{z}xJվn׋;SZnǏTzYĔfffR{E75vűQNKDckz孭yfe$)(n{~+8;KIH`^[wTLr{e\[[iBA?̶س̙r~fauy3)'x\Z;YDᥤVTR1BEvts%! }RA?ގkjtr{p333a[u{ b[wIks:::FlQ~|{BeMrqn~A\bi fffڋ*,tRNS8KgbKGDHgIFg>U cmPPJCmp0712HsXIDATx^w8T 8tυɉ >$<&1t9!:,`Ͱh!Tu%qQiUٲ-d-G LʴHF@`b LL0`b LL0`b LL0`b LLsN*28n+&˫ TxaJ<,xuwuT?_e7/JhucWU΍8럯݋0ǡuUӳrGpBh'Ӑ#8LdnI}O'~5sWqx`ycmMYObowTi{cc#XR8<b_LũjCBiwޯ{מv !8y8n:kaxN)Q)()|z# $ tV-%b8K`:A8VFY?,{@l<\h)x7@\W1sx"N0#q~d@3MKݛ ZFrYeʆR'e[_ n.%$p:6u*zDVzlej;Gѽ@4qeBdhEupn9=-NYё-:x3{6>_ݾ i⫶既ofv~Bܰn{$N.3;x <35j>n| y;6R©wX)0_=R9/PhTSdbX?s׃C Uڋ(?sVSϷ@`)q~S\p_--dz.k{"1>vOg7 S{H#gcY{,N\v}^%|U@+H6en}%|q8Az|dSã.|sS}:dO@C2}@[3Un-c1͜1@NReY~ZiOͶ]K 9s O˭C8}@g+Ov/l^w7iKβުnכؼ>8A­֛ HTsIخ9#8U_{4kvcC[y =aX:N펄50<`0~*@~եnczdcwdF Zzz1I8m[2鰧;]ilN'N N!_ yz6 =R-%Npf":?@;wټ:<ڬhSS Gq^vcl-u&ĺ| 8gsGٴ^"uʵݢ˲k}Seކ1? @` tV>f{U/ʸcuw:R{~:}R-4/8k?+'Ɖ5O:mWrbWyȦ켽\=Ѽ0v:օqy6۩Q{TNPUH{a L&eAhZ2Y$' bjx ((P:888c3W /G |ѮslCZ ~x)˨zQcyfYBTeKtG6HF;]oӅ'KSе蒻˗cGew)Tl!cN5SD<~Q2/k26~>2?c ly5fa׬00+#=_^kLwq`NcD01K8 ֜|$:᤿4_# ǣ .Gqiڽ˨1 C1%_T87d-󺍏)XL^vpj7M pO_(oFkco +.C03o"ptNN˿Zv";ʃx*:ho |Mca2g.λAb{_68߅O xzډCPhJs'j%R! VD c2 ?%,!/|h Tp=J^涹h8eHlfacYֆW0hmP$ԱQ uԉM4tNNє1qXK"se-J*%5iB>ӖԈtjQjB[f1|3]O"MB;ɀW)w; }K۩6AspĨȎQ2vjJ+< NI Ti9xTB|F+tDRxp63^ĝRú8: "bNx _C2F?] Z;״&)(vRO'FQ!1Bb#j,lR4i[C`7.?qnVwy K76U0҈&䢤L*y/SٶM) xHFXRLIF"HѨ:JDLƼ)䋼 3j'g!(8eqqZL9QbM uFÁ%#5-HĎƏ* LPHsƳBH ě!z8]Uc_[$c&: W>)›.]r_׌2&25.pwD>nW /2mg{8N-׌}Fy9{V3"8]ymwOp2BonSCWz[ z$8=gm#6EQZh&NW[S ƍ?Fpzvq8"Tw:*ރ!nSWnV;U)}iC\;8h"V18Rmsӳ$0URZM 5'S;iׄj35]RTrRʔZ % Avҁ/;1`$$ F6:p4hZQQrʓQMiG!8vfsKP۳}k^1NcS+TO5a8| &X)j%`j"xA-!E|\49# 4K|1I@=Ǥp`R>l7 PcVF 1*%h09fSlт:Uؾf%k5UXIbmgLǍr(]JAe4tC5#y﻽邯T;UAqGBUL%NP`l҂0tjZai[JHjMr1ҏZLH'l ETN_oJҵt 9i2 Gˤ5=ǫ/I|x's 2|zt|>fpz<,w@p"8MaddMjnM򅋈)~{޿3#S*ìಾ_.}^L箖x,Vo'6ug\AP_R}#8}8e SÌ =eU4:?.W\QBZ=ۭ-e3l["8}8@2av!G}XGrR29]`h eAo{OYv-`ol砦65S()_S\~y,ߣ#8!+j pZ4,t^.Si%Üχj1M&VuKªA n\e,poAg} /^; bZ@P]>erKmO~re]UPUֲ(2*u[ho^;E«mn֣[q|/X?hmXQ1,uH%@.gX6pk]\yuWg+N?kp,z5N$ʿW8 fH~8UEsB5'e.msCk4+H'g':_ͫ_Sĝ7$8=3N<9&l҄<'N'Ӝˋ[򱳫6*kWW\4#LDT|&̢õE>%\Z{̩V5ggP搊 _XQ1dњ[ĵpViٽ%rnVbGE$͹iZ-GG젹CI89M[ML 2zyX-}%Sl|ẁ^J3?php2G{Lq_wZp0þݜâQx"]K6C }ge`(|"awd}35f¶cd~'u`G,]m6ݰe͙:2j6wi20\OӸ"@ :!|YWYb8Ҍ}}Kv`E枌¦ [J;izE\ ewuy͍?;;wRr]wƒf]d-fCgc>{(oC'}}ک3/FrC-fD5~8c8ൠ`r>ef32MX0^d0 ,̒C%'{) %P;y TEEHJ( %Ȃ)G#fvb/7ӵrͱ^k~^vuN4`1#M:)X1JCb(%Rʼn9ؖ84rFnaZ`qL*E'e5$&}ƵxW !n8 n4Sh ^mSׄQֆ4amUCn3 NzqRF6]eq`NtTUVӎVQimTdd#ɚmRS>[~p^&wpc/^BR/ `8L("Bh lSm+Hꀐc_.KLq!Wp,Up|\f6W:D;OW'mW_umDp2 NQ1"Fp"8Ġ̷P'L~նAnBtI7^ 8LdDp"8=Lդ3+ިv/ZBxП7='CЍ[ct7橩7~`?gjACqԟ~YG ۿ-M Iټ1f5G懟A3Gi=?S ?UOz&&-Yfs6 NЏ~#3~~ >^??6= N0k\Xۜjgw~󟡳# ԃCh{?E=Nҙ1ۮy.YΏTKV~#=r~8?3?+-~sLȢG[-~5D++?O9#`"ϔLXG}snY ΍ kp kd>ڬ.rz w􌤳bgpyw>KHO2`(N㍳9l׭ѳƑrEQzo??weC} qF1Ncf$Pejߥ’28j\*H!X_Gp2cD^NQKq|z44 @уʷ'9ǑCX TޏnB2N>70hn/fk:Ŝӭ}ELU\ zV66>1? SԵx (uum^kܵ8<l[.-ڀ;8>>H`ݥ\[pMvztjA JCB:x!m88N9$Xò.ouvzZ^+ע-E2^ezqᒡd#DYN|>1gt-NghNA #DZVo'8q3~K] ɷ􆤳#OzNow)*: wұ Epz8}+"G{iZ~}~]r=ʋDp_뿾gރzs}_Qݻp/(|4NJw;__w߁Ry?ݿ_c~71N ~yo1yw1=@~;'ؿQ} !8-׿n a~;>@/:8{b 7iQ{>q`t>ny?BIy ;R;AgGp Jp8e!@weۮ>|vUv"Q'{~?/ _ǐwz13g1ߺ)%a88Nw]JSRUQp-No^;Id"O'ɤϟިÓoP;=_C]˝[IgټΎDp2[qtYdydn˕tvO)NLq #8N&Igg";_Ȋh'L$-Tdn"nIf+G(Rwg9 [Nt.0,r!ډhh'únANwSbXDp2 ݂'ݔ qfZR ӳCS_GܦfgRNzqyܘŪi9f'|&eפlpfNh2vƮ2܉|92)$&&efh]*'qfFȬ|7kɔFÙ8Q'J9ޔ j\ÌժNILNR &>a-45UsApzC8W~%?q =eYF?9O6 No'vX ʓ CQeh":;JJjIbԄ I DR:3J'UIۉLJA"PPQa\KO:j-9/m!Q8*1 :#$;b)FHJRk'шM':t^a9+>BVaՑdY\K)h4REӈS(ͪ8,Ȋ'-uI:q=lIs S-:e HɂC]MttR FĸPuT3: ѨJxNpz;8DX5(ih<4Qf3-D gh:T)Jcm A+`)Q=$''GB :DB5zǡ^F JhB8˝H#,p$koh/6S|+sLKO*9<%N;N2LB(~J\/"F*a2e9?I8bzp:4XЋ&,AOD Gpzأ>szB:b '#ϟHiUI VWQHwi&IgA"Z/D;UOSyq;Nm2u Ht NMuv4ė$3m8'FY] NfO9wFd. wVFph\,pϧi#u::zkӜh6Cp2RKFd' ,$XuCP"Ձ@h'C)TJ!>$bHP?{0r+!8=>)qr@d#Qhg8p'Uh¸:Ux%O#G)#K 8}8tIE@Y3Tg$'=a C@OpWnuu̪'N7.<["8%#2Ϗf\H #@/s?ҳwo{G3]IP)*M&b>q]GlY=o'g)u:/B9|rȊ4v' ÐLB vvC>mx#~2$dg^L#>QR^ 6ERy85IN"|\ӀڨçTc8&=/TyK8 XwB^ǁS/^gţ_ kY 9cҬM*#Ae*>_emzS稇 _fNo^^O~̜NdR'Y,A>υzBO_K^HQn7ufvv&X܄f-1]J4+E]sQ⫒]Y,n`ɟ "e^FVN'Xn,^Lvól.l2 w_RC"7o<',f7ׇ߮ڠij%"npb!cgCYiցztE>Qhی Ɂ+p2M]O )e|z]_`(*qlVv#TYڥ,ٜzwի]PL*@-nWMxj8ll쨹R,[%v۔LG E@H՟b)xxܟ/ypZY9`[uga]lƹ_VGQeϣ4{.Z.VQh)r6]3ɴ_Lزzf^3ì%at|}aSi^^24Vvy6giIaXy~'/xEa@6msOp͗ϔ9gv&=pƽlN*@]2)gPWVuE[]zN7\Czc(.5JmDi:(V`\8RgmG.Ʃ[LزTucx:fUr>)n8(HN?_zM)7*.a2"·ۆ#HTG3>'77C_6s4w\Uf [tQ8pQpd#pzx- (Wy/gԲl}X-w('3ݘՏ\Nܜًfy^ߴ-Gyt iLi6}I|^P0 'NXK1݅v>b"8>eelgGHPfy&eX'm89,;g~q p)j,Jmn/pxZ7s;]jK{4oHݼǖddvKy1Uu2á2X$?;zC qR'+o(_>8gZ4D\3Fa5g#zouh d+8  wN]xqw x_3Lc3>>)U&y;N:؅-  8kguwsa۴߬ffaw˄An~x_ib7خ{xOQ7l8.HPNX?/#pzz {Keze;V19blbg=0;tf4]&|^[9ޅnyF^p.X gqyժ;6uzAr\cgY<]VI/ |8R& ==?gNwj 8= c~?Mp"_< /^Ep"8 3"ډh)1,Ap"8nAnJ KNa[Dp'aX$8İd N)1,Ap"8nAnJ KnU٬ y̛.,o,^ 3LH] 3mcf} 냙 qsYRqL~g"† ӜӼNy6+9}A]H?sE4)3B7 NP'Y5@p2&vIjLK_ PdOԹOKjbqKMXtSNLڒ/e|W;Nߕ_ԁ9T< SY3P|%Nl*VDIQXDڡN*Jh/%SGq;lq6#x U .B:+is. ,U,'Pg 7RdJ DSX²w8KYAN`O`[u'd0YKvdZc'cQJZ WSk҄TVn ?bp*&\ʜXM4qbʄ>z'VZIj,"ۑ'ܨ4݉+.qRX"'KK7tiJ[I@D=Ye#6M`{55ܓim)GihJ"*x* $FI4ih$ġ"@%'ht3ĸ%N)PD!4dlҤ!1$+s*iȩI4B +9wD|RtJtDA^7R:NI,8؍Bʽ95 uT}NED7#Yq tTaGB(+N)/өB-٥!GB5)>R(1PP sّ8$:keu t0(8RՉpqo#)mĥ^ʼv2 ]rO4XVN4'P<;L%ԉFSiR4'5: X]Iީ$m:)^[SǫZ\HrPZ+6𮛿 TR9IΘEWZ2'RQ;qvU5ÎSRE!'mDY yiZt:B2t0AM:IFMI)okk)FS%靎'8qT6o(m4c| ' k͡XB[tǥr&5E Pȹ /;4 Gp2PID'C?:Nf jDp2N&$N'5@p22v"8jWo}gk+41kF˚Yln7l[df쯛Mg,xWܬI͚WN҆W,0Cz@0e'ih06qvM6"j$\^fD{ۚ,4BH/EX5^v |F8U/f̋kZ,>õ]ͼ3 !. "gfbyzqQPX7>XQ,&PᐡaUJxPYUw5] t-yhр06f42ƨ;;;jnms{.<^%ܼl"ӑjvw`0>i\ZJ|h1V+0e:NYo$er,h%Cw#o,l'?~߲kM^wuϏ>j6|fw^mFrJf3ld2[™ DaP3ˬW;AZ)L7pު[8ev-g) |pxqw}:~YrU;]0l2ۼV2 {5iLw6u_Zpd6N 3# {78j{[|nDܐi}hW` vPdPM{*7Ru l<\j ;]~v5Ys}㧰=}=p!h)nFY *pz.w]jrggV#8պ~ds!ډ|b#b'N NQ1"Fp"8Ġ d#b'N NQ1"Fp"8Ġ d#b'N NQ1"Fp"8Ġ d#b'N NQ1"Fp"8Ġi8`Ӭ6+#=۾lK}ad-žI,124/Ф|لwnvV(C&ٜI`ZN@_͍/dFpNc7/ eZCIs|T6#'?dFNZr>_}ie6M'̐eVD0%)qmEέ?5?/Gax L Sp!.βWHॿ!'.Mu"bH1$} 4hU)Mr|N]IN| hmSSbY %5vG Ȅq Xdp1!NbpB ZB6)'NMq]c(٫MQM:!4N$NiT@Zi']NIP NAdN2+B%^H55TM6Q L%4VÓ/NT A2x#oN).6b-'_A8PVt )lCuFN5!eZOQ0Jȡ!b=Nƍ:HkH>)jdĢи p։Qɘ>J,S%5NP9'{/S ~X:9D gr:MJTYHh M`N;N wxw Z ?R/>N~Vx)˓ LF㉚thKnM `&($9qr"QL+cCo!88C JDM.tZ AZ!N坊H \XAm L 8qJ\cU0@m:=rL!<+kz6SY1XN!C~xtIܼQ85JJpʈcG7jA0K+8%-NTJDi@+at u ).l0,`LX<-: cijI1e{pfզ`bjSl T`U8V;常0I: P 8bNOSj~IPFi.H쉣,9#@Jn t%`|A!QRS0D_'.$ >7ӹ gq߷k}2Ȓ)/?ܯ':/g7df?'—>ل-N73g^ c}pVL8=Y!8='7U'Y,A>' 8XD;N&$ډDp2N&V&N'5@p22v"8LIdb LLN'kdbeDp"8X'+h' 8Xk'dD&YIs6N1)Lg_nӴK"7\IҤ6-'@+ؼפ1)E6I M!s֡I!jR>l>ܬpnW\c?W5mzk Fp~8! 85YLpd ~<=54U;U8T=ټ9ܛw }!S:;nwYn׭_px1KNϗG1ĩjo}=V3z}'wk{8u_LZ]Ex]`p:=eeQe8պNm~vk,3qrG+UeDZ*VR-N6z-d e Nj}wg^2P˭^X|PӭzURB8lq Z)u=koaʓ >/ʩ]27=zkͥʭ(uVަߙSز4MgƩ٥}gG3r\t dv}n?kSw#Mzhe۳㔛{y\[q'>ڡzؗǭ2ߏfw ǚGaY5Tv)qEЧxˇkh굶 N| QN!4Edۡbc|,_FY cn4 h)wl,80f10<n}5ek2HT8O-zSX;/ohvwollvF"n? {dQ}TUf}8.ydQ>N}ņeMYq)c]=H$LHX)<G@y9eaiRpga}6DrxD)Ѩ:Y?Ї/XzsYO3=f1;PHXW{`0hI>,UMyqR,9i& Suw$*(3z֒a,l8e9*|݁ l[4jE$ .9pգ6ݣי:Ȳr}M=]HTŶwA@?1|e_rT]v+\Ԯ9%֓7/6[^߂GJ^akkbg ub V5 SfwNu|nO '6vn.=̛MXmnnwwK.#nH\ʸN7L T/"KC} ` [5c4 tF0SR̀>Xj2'uj)8Uc)~oE LNƪ4)Ӄ)/"8F^T;:3cЇNF(0Mq:=l\tYs.*gBp2 # N(ߵC~utXqE7ː oX?KLq3Q1/x/>S{F'v"̓ya}."X1QLNFY1 Gp"8ĨdrfWFLo'3?_eyad3̰񯿿0m9XLj4`[7V S;~{ tr-]BN*SZ{"q}$_ꖻLP)FTaJm %AMCJVxZhM<!OSzPuI(SHkm6TTj꤭Ҕ~2#jZ(ۋX{b?i9L{JK93ع&>xg +I*A;;_'Mv8;Psr*w,.OL'B<J@Tl9'8öOV*-wNާ#9K4 | ډC=V88Ʌ 7K.]Aw{u 2If9@I!LOBTj8B D!.QS*V܉SHrp_6mQ pU1$}Ϲ>n o={|-x@ Դ&y48!i|7;~[q- OT_}YN_} 8Bp55W_W߄N5&|M7@pzM՗7kkj, _ FSIENDB`Dd*<P  3 3"(( i@@@ gQe1$$CJKHPJ_HaJmH nHsH tH\`\ jL 1dd1$@&[$\$+5B*CJKH$OJPJQJ\^JaJphA@ -k=W[W"U`" #P} >*B*phf\o\ titledd1$[$\$+5B*CJKHOJPJQJ\^JaJph3\^`\ gQe (Web)dd1$[$\$%B*CJKHOJPJQJ^JaJphPo"P tmdd1$[$\$%B*CJKHOJPJQJ^JaJphho2h captiondd1$[$\$^+6B*CJKHOJPJQJ]^JaJphe`B HTML Preformatted: 2( Px 4 #\'*.25@91$%B*CJKHOJPJQJ^JaJphc +,9( 1hOOO$PNPtQQQQ1RHRSUWaXXGYUYbYtYYYYYY5Z6Z=ZiZZ [[[6[[[[[\ \N\O\[\\\\\\]2]_]`]k]^^aaaccc00000000000000000000000000000000000000000000000000000000000000000000000000000T]egfiuzY)16(::?BLHV] _N`_agggjklmnopqrstvwxy{ghf rTacTegP  p '))  + ,?a,b9bcXXXXXXXXXXXXXXXCXYcgl/:? H   >ccG I IP{)2"!#0#F#_#n#########$$$%%-%B%L%Y%a%~%%*+*+0+`+g+++++++++++,,,,$-+-V-a-q-----------^c3333333333333333333333333333333333333333333333[[^ctest2yC:\Documents and Settings\Administrator\Lhb\Moving from the BDE and dbExpress to ADO.NET and the Borland Data Provider.doc+,556(6)616A6P6Q6U6e66666666666GYUYbYtYYYYYY5Z6Z=ZiZZ [[[6[[[[[\ \N\O\[\\\\\\]2]_]`]accc@   c`@UnknownGz Times New Roman5Symbol3& z ArialI& ?Arial Unicode MSC.e0}fԚPMingLiU?5 z Courier New 1hSSqVR*#?!),.:;?]}    " % & ' 2 t%00 0 0 00000013468:<>@BDOPQRTUVWZ\^ \]d([{  5 0 0 00000579;=?ACY[][77xe2Qhttp://www-106test2test2Oh+'0t  0 < HT\dlhttp://www-106ttptest2/westest Normal.dot1test2.d1stMicrosoft Word 9.0@@K@KqVR՜.+,D՜.+,8 hp|  1/*e http://www-106 D 8@ _PID_HLINKSAPfvA0 mailto:jeremy@mcgee.demon.co.uk|6*Whttp://www-106.ibm.com/developerworks/db2/library/techarticle/0308mcgee/0308mcgee.html|6'Whttp://www-106.ibm.com/developerworks/db2/library/techarticle/0306swart/0306swart.htmlM$Yhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0305swart1/0305swart1.htmlkr!Ihttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ conclusionJIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section8EIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section7DIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section6GIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section5FIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section4AIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section3@ Ihttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section2C Ihttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ section1 Ihttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ introductionogIhttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/ authorname|6Whttp://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/0309mcgee.htmlj6[http://www-106.ibm.com/developerworks/db2/library/techarticle/0309mcgee/images/figure1.gif  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|~Root Entry FRKData } _1Table[WordDocument2SummaryInformation(DocumentSummaryInformation8CompObjfObjectPoolRKRK  FMicrosoft Word MSWordDocWord.Document.89q